/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __DX_MODEL_H__
#define __DX_MODEL_H__

#pragma once

#include <d3dx9.h>
#include <string>

#include "DXResource.h"
#include "IModel.h"

namespace directx {

/** User defined vertex format! */
const D3DVERTEXELEMENT9 VertexDeclaration[] = 
{
	{ 0, 0  * sizeof(float), D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },  // pos
	{ 0, 3  * sizeof(float), D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0 },  // normal
	{ 0, 6  * sizeof(float), D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT,  0 },  // tangent
	{ 0, 9  * sizeof(float), D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 },  // binormal
	{ 0, 12  * sizeof(float), D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },  // tex0
	{ 0, 14  * sizeof(float), D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },  // tex1
	{ 0, 16  * sizeof(float), D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 },  // tex2
	{ 0, 18  * sizeof(float), D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 },  // tex3

	D3DDECL_END()
};

struct MESH_VERTEX
{
	D3DXVECTOR3 position; 
	D3DXVECTOR3 normal; 
	D3DXVECTOR3 tangent;	// tangent vector (basis vector s)
	D3DXVECTOR3 binormal;	// binormal vector (basis vector t)
	D3DXVECTOR2 tex0;		// texture coords
	D3DXVECTOR2 tex1;		// texture coords
	D3DXVECTOR2 tex2;		// texture coords
	D3DXVECTOR2 tex3;		// texture coords
};

class Model 
	: public IModel, public DXResource
{
public:
	Model();
	Model(const Model& m);
	~Model(void);

	void draw();
	inline void update(double dt) { }
	bool load(const std::string &filename);

	// Optimizes the mesh data for vertex buffer useage
	bool optimizeMesh();

	bool computeNormals();
	bool computeTangents();

	void release();
	void reset();

public:
	// Loads the materials from the mesh file
	bool loadMaterials(LPD3DXBUFFER pD3DXMtrlBuffer);

	// Returns the transformation matrix
	D3DXMATRIXA16 getTransformation() const;

	void calculateNormals(MESH_VERTEX *pVertex, int nVertices, const WORD *pTriangle, int nTriangles);

	void calculateTangents(MESH_VERTEX *pVertex, int nVertices, const WORD *pTriangle, int nTriangles);
private:
	std::string sFilename;

	LPD3DXMESH          pMesh;			// Our mesh object in sysmem
	D3DMATERIAL9*       pMeshMaterials; // Materials for our mesh
	LPDIRECT3DTEXTURE9* pMeshTextures;	// Textures for our mesh
	DWORD               dwNumMaterials;	// Number of mesh materials
};

} // namespace

#endif
